using Flurl;
using Flurl.Http;
using OkFlurl;
using System.Text.Json;
using System.Text.Json.Nodes;

namespace TestRest
{
    public partial class RestHelper
    {
        #region static method

        private readonly static object _locker = new();

        private readonly static Dictionary<string, RestHelper> _dict = [];

        public static RestHelper GetCache(string url)
        {
            var ok = _dict.TryGetValue(url, out var val);
            if (!ok)
            {
                lock (_locker)
                {
                    if (!_dict.ContainsKey(url))
                    {
                        _dict.Add(url, new RestHelper(url));
                    }
                }
                val = _dict[url];
            }
            return val;
        }

        private static T GetData<T>(JsonNode node, FlurlRequest req)
        {
            if (node["code"].GetValue<int>() != 0)
            {
                throw new Exception($"{req.Url}==>{node["msg"].GetValue<string>()}");
            }
            var data = node["data"];
            return JsonSerializer.Deserialize<T>(data, FlurlExt.JsonOptions);
        }

        #endregion

        #region common

        public RestHelper(string url)
        {
            BaseUrl = url;
        }

        public string BaseUrl { get; }

        public string Token { get; set; }

        private void InitRequest(FlurlRequest req)
        {
            if (!string.IsNullOrEmpty(Token))
            {
                req.WithHeader("token", Token);
            }
        }
        
        private FlurlRequest CreateRequest(string path)
        {
            var req = new FlurlRequest(BaseUrl);
            req.AppendPathSegment(path);
            InitRequest(req);
            return req;
        }

        public async Task<T> GetJsonAsync<T>(string path, object par, CancellationToken token = default)
        {
            var req = CreateRequest(path);
            var node = await FlurlExt.GetJsonAsync<JsonNode>(req, par, token);
            return GetData<T>(node, req);
        }

        public async Task<Stream> GetStreamAsync(string path, object par, CancellationToken token = default)
        {
            var req = CreateRequest(path);
            return await FlurlExt.GetStreamAsync(req, par, token);
        }

        public async Task<byte[]> GetBytesAsync(string path, object par, CancellationToken token = default)
        {
            var req = CreateRequest(path);
            return await FlurlExt.GetBytesAsync(req, par, token);
        }

        public async Task<(Stream stream, string name, long? length)> GetDownloadStreamAsync(string path, object par, CancellationToken token = default)
        {
            var req = CreateRequest(path);
            return await FlurlExt.GetDownloadStreamAsync(req, par, token);
        }

        public async Task<(byte[] bytes, string name)> GetDownloadBytesAsync(string path, object par, CancellationToken token = default)
        {
            var req = CreateRequest(path);
            return await FlurlExt.GetDownloadBytesAsync(req, par, token);
        }

        public async Task<string> GetDownloadDiskAsync(string path, object par, string folderPath, string fileName = null, FlurlProgress progress = null, int bufferSize = 4096, CancellationToken token = default)
        {
            var req = CreateRequest(path);
            return await FlurlExt.GetDownloadDiskAsync(req, par, folderPath, fileName, progress, bufferSize, token);
        }

        public async Task<T> PostGetJsonAsync<T>(string path, object par, CancellationToken token = default)
        {
            var req = CreateRequest(path);
            var node = await FlurlExt.PostGetJsonAsync<JsonNode>(req, par, token);
            return GetData<T>(node, req);
        }

        public async Task<Stream> PostGetStreamAsync(string path, object par, CancellationToken token = default)
        {
            var req = CreateRequest(path);
            return await FlurlExt.PostGetStreamAsync(req, par, token);
        }

        public async Task<byte[]> PostGetBytesAsync(string path, object par, CancellationToken token = default)
        {
            var req = CreateRequest(path);
            return await FlurlExt.PostGetBytesAsync(req, par, token);
        }

        public async Task<(Stream stream, string name, long? length)> PostDownloadStreamAsync(string path, object par, CancellationToken token = default)
        {
            var req = CreateRequest(path);
            return await FlurlExt.PostDownloadStreamAsync(req, par, token);
        }

        public async Task<(byte[] bytes, string name)> PostDownloadBytesAsync(string path, object par, CancellationToken token = default)
        {
            var req = CreateRequest(path);
            return await FlurlExt.PostDownloadBytesAsync(req, par, token);
        }

        public async Task<string> PostDownloadDiskAsync(string path, object par, string folderPath, string fileName = null, FlurlProgress progress = null, int bufferSize = 4096, CancellationToken token = default)
        {
            var req = CreateRequest(path);
            return await FlurlExt.PostDownloadDiskAsync(req, par, folderPath, fileName, progress, bufferSize, token);
        }

        public async Task<T> FormGetJsonAsync<T>(string path, object par, FlurlForm form = null, CancellationToken token = default)
        {
            var req = CreateRequest(path);
            var node = await FlurlExt.FormGetJsonAsync<JsonNode>(req, par, form, token);
            return GetData<T>(node, req);
        }

        public async Task<Stream> FormGetStreamAsync(string path, object par, FlurlForm form = null, CancellationToken token = default)
        {
            var req = CreateRequest(path);
            return await FlurlExt.FormGetStreamAsync(req, par, form, token);
        }

        public async Task<byte[]> FormGetBytesAsync(string path, object par, FlurlForm form = null, CancellationToken token = default)
        {
            var req = CreateRequest(path);
            return await FlurlExt.FormGetBytesAsync(req, par, form, token);
        }

        public async Task<(Stream stream, string name, long? length)> FormDownloadStreamAsync(string path, object par, FlurlForm form = null, CancellationToken token = default)
        {
            var req = CreateRequest(path);
            return await FlurlExt.FormDownloadStreamAsync(req, par, form, token);
        }

        public async Task<(byte[] bytes, string name)> FormDownloadBytesAsync(string path, object par, FlurlForm form = null, CancellationToken token = default)
        {
            var req = CreateRequest(path);
            return await FlurlExt.FormDownloadBytesAsync(req, par, form, token);
        }

        public async Task<string> FormDownloadDiskAsync(string path, object par, string folderPath, string fileName = null, FlurlForm form = null, int bufferSize = 4096, CancellationToken token = default)
        {
            var req = CreateRequest(path);
            return await FlurlExt.FormDownloadDiskAsync(req, par, folderPath, fileName, form, bufferSize, token);
        }

        #endregion

        public async Task<T> Home_A<T>(object par, CancellationToken token = default)
        {
            return await PostGetJsonAsync<T>("/home/a", par, token);
        }

        public async Task<T> Home_A2<T>(object par, CancellationToken token = default)
        {
            return await PostGetJsonAsync<T>("/home/a2", par, token);
        }

        public async Task<T> Home_A3<T>(object par, CancellationToken token = default)
        {
            return await PostGetJsonAsync<T>("/home/a3", par, token);
        }

        public async Task<T> Home_A4<T>(object par, CancellationToken token = default)
        {
            return await PostGetJsonAsync<T>("/home/a4", par, token);
        }

        public async Task<T> Home_A5<T>(object par, CancellationToken token = default)
        {
            return await PostGetJsonAsync<T>("/home/a5", par, token);
        }

        public async Task<T> Home_A6<T>(object par, CancellationToken token = default)
        {
            return await PostGetJsonAsync<T>("/home/a6", par, token);
        }

        public async Task<T> Home_A7<T>(object par, CancellationToken token = default)
        {
            return await PostGetJsonAsync<T>("/home/a7", par, token);
        }

        public async Task<T> Home_Add<T>(object par, CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/home/add", par, token);
        }

        public async Task<T> Home_Add2<T>(object par, CancellationToken token = default)
        {
            return await PostGetJsonAsync<T>("/home/add2", par, token);
        }

        public async Task<T> Home_Del<T>(object par, CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/home/del", par, token);
        }

        public async Task<T> Home_TestAsync<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/home/test", null, token);
        }

        public async Task<T> Home_VAsync<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/home/v", null, token);
        }

        public async Task<T> Home_MyAsync<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/home/my", null, token);
        }

        public async Task<T> Home_db<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/home/db", null, token);
        }

        public async Task<T> Home_db2<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/home/db2", null, token);
        }

        public async Task<T> Home_db3<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/home/db3", null, token);
        }

        public async Task<T> Home_dbQuery<T>(object par, CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/home/dbQuery", par, token);
        }

        public async Task<T> Home_Autofac<T>(object par, CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/home/autofac", par, token);
        }

        public async Task<T> Home_Http<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/home/http", null, token);
        }

        public async Task<T> Home_AddP<T>(object par, CancellationToken token = default)
        {
            return await PostGetJsonAsync<T>("/home/addP", par, token);
        }

        public async Task<T> Home_All<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/home/all", null, token);
        }

        public async Task<T> Home_page<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/home/page", null, token);
        }

        public async Task<T> Home_Down<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/home/down", null, token);
        }

        public async Task<T> Home_TestIAsync1<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/home/testIAsync1", null, token);
        }

        public async Task<T> Home_TestIAsync2<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/home/testIAsync2", null, token);
        }

        public async Task<T> Home_TestIAsyncDb<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/home/testIAsyncDb", null, token);
        }

        public async Task<T> Home_TestIAsyncDb2<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/home/testIAsyncDb2", null, token);
        }

        public async Task<T> Home_TestGet<T>(object par, CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/home/testGet", par, token);
        }

        public async Task<T> Test_Index<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test/index", null, token);
        }

        public async Task<T> Test_AA<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test/aA", null, token);
        }

        public async Task<T> Test_Q<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test/q", null, token);
        }

        public async Task<T> Test_F<T>(CancellationToken token = default)
        {
            return await PostGetJsonAsync<T>("/test/f", null, token);
        }

        public async Task<T> Test_R1<T>(object par, CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test/r1", par, token);
        }

        public async Task<T> Test_R2<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test/r2", null, token);
        }

        public async Task<T> Test_R3<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test/r3", null, token);
        }

        public async Task<T> Test_RwR4<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test/rwR4", null, token);
        }

        public async Task<T> Test_Upload<T>(CancellationToken token = default)
        {
            return await PostGetJsonAsync<T>("/test/upload", null, token);
        }

        public async Task<T> Test_Uploads<T>(CancellationToken token = default)
        {
            return await PostGetJsonAsync<T>("/test/uploads", null, token);
        }

        public async Task<T> Test_Json<T>(object par, CancellationToken token = default)
        {
            return await PostGetJsonAsync<T>("/test/json", par, token);
        }

        public async Task<T> Test_Bind<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test/bind", null, token);
        }

        public async Task<T> Test_Bind2<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test/bind2", null, token);
        }

        public async Task<T> Test_Get<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test/get", null, token);
        }

        public async Task<T> Test_GetPeople<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test/getPeople", null, token);
        }

        public async Task<T> Test_GetPeople2<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test/getPeople2", null, token);
        }

        public async Task<T> Test_Upload111<T>(CancellationToken token = default)
        {
            return await PostGetJsonAsync<T>("/test/upload111", null, token);
        }

        public async Task<T> Test_ZZ<T>(CancellationToken token = default)
        {
            return await PostGetJsonAsync<T>("/test/zZ", null, token);
        }

        public async Task<T> Test_J<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test/j", null, token);
        }

        public async Task<T> Test_T<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test/t", null, token);
        }

        public async Task<T> Test_D<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test/d", null, token);
        }

        public async Task<T> Test_Bd<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test/bd", null, token);
        }

        public async Task<T> Test_I<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test/i", null, token);
        }

        public async Task<T> Test_Dbb<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test/dbb", null, token);
        }

        public async Task<T> Test_Dbb22<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test/dbb22", null, token);
        }

        public async Task<T> Student_index<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/student/index", null, token);
        }

        public async Task<T> Student_Add<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/student/add", null, token);
        }

        public async Task<T> Student_baidu<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/student/baidu", null, token);
        }

        public async Task<T> Student_Down<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/student/down", null, token);
        }

        public async Task<T> Student_Jd<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/student/jd", null, token);
        }

        public async Task<T> Test2_Db<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test2/db", null, token);
        }

        public async Task<T> Test2_GetName<T>(CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test2/getName", null, token);
        }

        public async Task<T> Test2_GetUpload<T>(FlurlForm form = null, CancellationToken token = default)
        {
            return await FormGetJsonAsync<T>("/test2/getUpload", null, form, token);
        }

        public async Task<T> Test2_GetUpload2<T>(object par, FlurlForm form = null, CancellationToken token = default)
        {
            return await FormGetJsonAsync<T>("/test2/getUpload2", par, form, token);
        }

        public async Task<(Stream stream, string name, long? length)> Test2_GetUpload3(object par, FlurlForm form = null, CancellationToken token = default)
        {
            return await FormDownloadStreamAsync("/test2/getUpload3", par, form, token);
        }

        public async Task<T> Test2_Getdddd<T>(object par, CancellationToken token = default)
        {
            return await GetJsonAsync<T>("/test2/getdddd", par, token);
        }

        public async Task<(Stream stream, string name, long? length)> Test2_GetDownload(CancellationToken token = default)
        {
            return await GetDownloadStreamAsync("/test2/getDownload", null, token);
        }

        public async Task<(Stream stream, string name, long? length)> Test2_PostDownload(CancellationToken token = default)
        {
            return await PostDownloadStreamAsync("/test2/postDownload", null, token);
        }
    }
}